package com.xiaoshuidi.cloud.module.contract.service.roommate;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.common.util.json.JsonUtils;
import com.xiaoshuidi.cloud.framework.security.core.LoginUser;
import com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils;
import com.xiaoshuidi.cloud.framework.tenant.core.util.TenantUtils;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.RoomContractRespVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.roommate.vo.*;
import com.xiaoshuidi.cloud.module.contract.convert.roommeta.ContractRoommateConvert;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.ContractRoomDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.CustomerCompanyDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.roommeta.ContractRoommateDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.roommeta.ContractRoommateLogDO;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.bill.RentOrderMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.ContractRoomMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.roommeta.ContractRoommateLogMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.roommeta.ContractRoommateMapper;
import com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants;
import com.xiaoshuidi.cloud.module.contract.enums.contract.*;
import com.xiaoshuidi.cloud.module.contract.service.contract.ContractRoomService;
import com.xiaoshuidi.cloud.module.contract.service.contract.CustomerCompanyService;
import com.xiaoshuidi.cloud.module.finance.api.finance.FinanceAccountApi;
import com.xiaoshuidi.cloud.module.finance.api.finance.FinanceAccountWithdrawApi;
import com.xiaoshuidi.cloud.module.finance.api.finance.dto.FinanceAccountDTO;
import com.xiaoshuidi.cloud.module.finance.enums.finance.FinanceCustomerTypeEnum;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.AddPassword;
import com.xiaoshuidi.cloud.module.iot.common.ResultModel;
import com.xiaoshuidi.cloud.module.iot.enums.ErrorCodeEnum;
import com.xiaoshuidi.cloud.module.member.api.message.MemberMessageApi;
import com.xiaoshuidi.cloud.module.member.api.message.dto.MemberMessageDTO;
import com.xiaoshuidi.cloud.module.member.api.mobilemodifyrecord.MobileModifyRecordApi;
import com.xiaoshuidi.cloud.module.member.api.mobilemodifyrecord.vo.MobileModifyRecordCreateReqVO;
import com.xiaoshuidi.cloud.module.member.api.user.MemberUserApi;
import com.xiaoshuidi.cloud.module.member.api.user.dto.MemberUserReqDTO;
import com.xiaoshuidi.cloud.module.member.api.user.dto.MemberUserRespDTO;
import com.xiaoshuidi.cloud.module.rooms.api.roomhouse.RoomHouseApi;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.RoomStateRecordApi;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.dto.LivingWithInfoDTO;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.dto.RoomTenantsInfoDTO;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.vo.UpdateRoomTenantReqVO;
import com.xiaoshuidi.cloud.module.rooms.api.sdiot.IotRoomDeviceApi;
import com.xiaoshuidi.cloud.module.rooms.vo.RoomHouseRespVo;
import com.xiaoshuidi.cloud.module.system.api.user.AdminUserApi;
import com.xiaoshuidi.cloud.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.xiaoshuidi.cloud.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.xiaoshuidi.cloud.module.contract.enums.ApiConstants.ONE;
import static com.xiaoshuidi.cloud.module.contract.enums.ApiConstants.ZERO;
import static com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants.*;

/**
 * 合同同住人数据 Service 实现类
 *
 * @author test123
 */
@Service
@Slf4j
public class ContractRoommateServiceImpl implements ContractRoommateService {

    @Resource
    private ContractRoommateMapper roommateMapper;
    @Resource
    private ContractRoomService contractRoomService;
    @Resource
    private RoomHouseApi roomHouseApi;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private ContractRoommateLogMapper roommateLogMapper;
    @Resource
    private ContractRoomMapper contractRoomMapper;
    @Resource
    private ContractRoommateMapper contractRoommateMapper;
    @Resource
    private RentOrderMapper rentOrderMapper;
    @Resource
    private FinanceAccountApi financeAccountApi;
    @Resource
    private IotRoomDeviceApi iotRoomDeviceApi;
    @Resource
    private MemberUserApi memberUserApi;
    @Resource
    private MemberMessageApi memberMessageApi;
    @Resource
    private RoomStateRecordApi roomStateRecordApi;
    @Resource
    private CustomerCompanyService customerCompanyService;
    @Resource
    private FinanceAccountWithdrawApi financeAccountWithdrawApi;
    @Resource
    private MobileModifyRecordApi mobileModifyRecordApi;

    @Override
    public Long createRoommate(ContractRoommateCreateReqVO createReqVO) {
        ContractRoomDO contractRoomDO = contractRoomMapper.selectById(createReqVO.getRoomContractId());
        if (Objects.isNull(contractRoomDO)) {
            throw exception(CONTRACT_DOES_NOT_EXISTS);
        }
        //需判断同住人表里 该房间未退房的不能存在相同手机号
        List<ContractRoommateDO> contractRoommateDOS =checkPhoneRepeat(createReqVO.getRoomContractId(),createReqVO.getRoommatePhone());
        // 插入
        ContractRoommateDO roommate = ContractRoommateConvert.INSTANCE.convert(createReqVO);
        roommate.setRoomId(contractRoomDO.getRoomId());
        if (CustomerTypeEnum.COMPANY.getCode().equals(contractRoomDO.getCustomerType())) {
            roommate.setContractCustomerType(CustomerTypeEnum.COMPANY.getCode());
            //如果是企业的子合同，新增同住人时该房间没有人，则新增的第一个人是主住人 寝室长
            if(CollectionUtils.isEmpty(contractRoommateDOS)){
                roommate.setRoommateType(1);
            }
        }
        //根据手机号获取用户id
        MemberUserRespDTO memberUser = getMemberUser(createReqVO.getRoommatePhone(), createReqVO.getRoommateName());
        roommate.setMemberId(memberUser.getId());
        //如果合同已入住，需下发密码给同住人，且同住人是已入住状态
        if (ContractStatusEnum.CHECK_IN.getCode().equals(contractRoomDO.getContractStatus())) {
            LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
            if (loginUser == null) {
                throw new ServiceException(ErrorCodeConstants.USER_NOT_LOGIN);
            }
            //修改同住人为已入住
            roommate.setStatus("2");
        }
        //如果是企业，新增同住人需要签约安全协议之后才能更改状态为已入住
        if (CustomerTypeEnum.COMPANY.getCode().equals(contractRoomDO.getCustomerType())){
            roommate.setStatus("1");
        }
        roommateMapper.insert(roommate);

        //插入完成后，更新租客信息到房源
        updateRoommateData(contractRoomDO);
        //如果是企业合同，需生成迁入记录
        if (CustomerTypeEnum.COMPANY.getCode().equals(contractRoomDO.getCustomerType())) {
            roommate.setContractCustomerType(CustomerTypeEnum.COMPANY.getCode());
            //记录迁入
            dataLogging(roommate, 1);
            //如果是企业的子合同，新增同住人时该房间没有人，则新增的第一个人是主住人 寝室长
            if(CollectionUtils.isEmpty(contractRoommateDOS)){
                //如果是寝室长，则需要将合同的memberId和未支付的杂费账单memberId更改当前用户
                contractRoomDO.setMemberId(memberUser.getId());
                contractRoomMapper.updateById(contractRoomDO);
                rentOrderMapper.updateMemberIdByContractIdUnPaid(contractRoomDO.getId(),memberUser.getId());
            }
        }
        // 返回
        return roommate.getId();
    }

    @Override
    public void updateRoommateData(ContractRoomDO contractRoomDO) {

        if (contractRoomDO == null){
            log.info("查询的房间合同为空，同步房源信息失败！！！");
            return;
        }
        //查询出合同房间中的所有的已入住的人
        LambdaQueryWrapper<ContractRoommateDO> qw = new LambdaQueryWrapper<>();
        qw.eq(ContractRoommateDO::getRoomContractId, contractRoomDO.getRoomId())
                .ne(ContractRoommateDO::getStatus, 3);
        List<ContractRoommateDO> contractRoommateDOS1 = roommateMapper.selectList(qw);
        if (CollectionUtils.isNotEmpty(contractRoommateDOS1)){
            UpdateRoomTenantReqVO updateRoomTenantReqVO = new UpdateRoomTenantReqVO();
            updateRoomTenantReqVO.setRoomId(contractRoomDO.getRoomId());
            RoomTenantsInfoDTO roomTenantsInfoDTO = new RoomTenantsInfoDTO();
            // 企业合同 企业名称传参
            if (CustomerTypeEnum.COMPANY.getCode().equals(contractRoomDO.getCustomerType()) && Objects.nonNull(contractRoomDO.getCustomerCompanyId())){
                CustomerCompanyDO companyDoById = customerCompanyService.getCompanyDoById(contractRoomDO.getCustomerCompanyId());
                if (Objects.nonNull(companyDoById)){
                    roomTenantsInfoDTO.setCompanyName(companyDoById.getCompanyName());
                }
            }

            for (ContractRoommateDO m : contractRoommateDOS1) {
                if (m.getRoommateType() == 1){
                    roomTenantsInfoDTO.setName(m.getRoommateName());
                    roomTenantsInfoDTO.setMobile(m.getRoommatePhone());
                }
                if (m.getRoommateType() == 0){
                    LivingWithInfoDTO living = new LivingWithInfoDTO();
                    living.setName(m.getRoommateName());
                    living.setMobile(m.getRoommatePhone());
                    roomTenantsInfoDTO.getLivingWithInfoDTOs().add(living);
                }
            }
            roomStateRecordApi.updateRoomTenant(updateRoomTenantReqVO);
        }
    }

    @Override
    public void refundRoommateEmigration(Collection<Long> ids) {
        LambdaUpdateWrapper<ContractRoommateDO> qw = new LambdaUpdateWrapper<>();
        qw.in(ContractRoommateDO::getId,ids)
                .set(ContractRoommateDO::getStatus, 3);
        roommateMapper.update(null,qw);
        List<ContractRoommateDO> contractRoommateDOS = roommateMapper.selectList(new LambdaQueryWrapper<ContractRoommateDO>().in(ContractRoommateDO::getId, ids));
        dataLoggingBatch(contractRoommateDOS,0);
    }

    @Override
    public List<ContractRoommateDO> getAllCompanyCheckinRoom(Long memberId) {
        return contractRoommateMapper.selectAllCompanyCheckinRoom(memberId);
    }

    @Override
    public void updateMemberUser(Long userId, String mobile, String userName, Long oldUserId) {
        contractRoommateMapper.updateMemberUser(userId,mobile,userName,oldUserId);
    }

    /**
     * 下发密码
     */
    public void issuePassword(Long roomId, String userName, String phone, LocalDate startTime, LocalDate endTime, String nickName) {
        try {
            long longStartTime = startTime.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
            long longEndTime = endTime.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
            AddPassword addPassword = new AddPassword();
            addPassword.setRoomId(roomId);
            addPassword.setUserName(userName);
            addPassword.setMobile(phone);
            addPassword.setStartTime(longStartTime);
            addPassword.setEndTime(longEndTime);
            addPassword.setOperatorName(nickName);
            log.info("同住人下发密码：{}", JSONObject.toJSONString(addPassword));
            ResultModel<AddPassword> resultModel = iotRoomDeviceApi.addPassword(addPassword);
            log.info("同住人下发密码返回：{}", JSONObject.toJSONString(resultModel));
        } catch (ServiceException e) {
            log.error("====同住人下发密码失败====", e);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRoommate(ContractRoommateUpdateReqVO updateReqVO) {
        // 校验存在
        ContractRoommateDO roommateDO = roommateMapper.selectById(updateReqVO.getId());
        if (roommateDO == null) {
            throw exception(ROOMMATE_NOT_EXISTS);
        }
        roommateDO.getRoommatePhone();
        // 更新
        ContractRoommateDO updateObj = ContractRoommateConvert.INSTANCE.convert(updateReqVO);
        roommateMapper.updateById(updateObj);
        ContractRoomDO contractRoomDO = new ContractRoomDO();
        contractRoomDO.setId(updateObj.getRoomContractId());
        contractRoomDO.setEmergencyContactName(updateReqVO.getEmergencyContactName());
        contractRoomDO.setEmergencyContactPhone(updateReqVO.getEmergencyContactPhone());
        contractRoomDO.setEmergencyContactRelationship(updateReqVO.getEmergencyContactRelationship());

        if (updateReqVO.getRoommateType() == 1) {
            changeRoommateType(updateReqVO.getId());
        }else {
            LambdaQueryWrapper<ContractRoommateDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ContractRoommateDO::getRoomContractId,updateReqVO.getRoomContractId())
                    .eq(ContractRoommateDO::getStatus,RoommateStatusEnum.CHECKED_ID.getCode());
            List<ContractRoommateDO> roommateDOS = roommateMapper.selectList(queryWrapper);
            if(CollectionUtils.isNotEmpty(roommateDOS)&&roommateDOS.size()==1){
                throw exception(ROOMMATE_LEADER_CHANGE_ERROR);
            }
        }
        //如果是企业合同 寝室长，则需要将合同的memberId和未支付的杂费账单memberId更改当前用户
        ContractRoomDO roomDO = contractRoomMapper.selectById(updateObj.getRoomContractId());
        if(CustomerTypeEnum.COMPANY.getCode().equals(roomDO.getCustomerType())&&updateReqVO.getRoommateType() == 1){
            contractRoomDO.setMemberId(roommateDO.getMemberId());
            rentOrderMapper.updateMemberIdByContractIdUnPaid(contractRoomDO.getId(),roommateDO.getMemberId());
        }
        contractRoomMapper.updateById(contractRoomDO);

        log.info("[修改手机号] 请求对象:{}, 原合同信息:{}", JsonUtils.toJsonString(updateReqVO), JsonUtils.toJsonString(roommateDO));
        // 记录手机号修改
        if(ObjectUtil.isAllNotEmpty(updateReqVO.getRoommateIdNumber(), roommateDO.getRoommateIdNumber())
                && updateReqVO.getRoommateIdNumber().equals(roommateDO.getRoommateIdNumber())
                && ObjectUtil.isAllNotEmpty(updateReqVO.getRoommatePhone(), roommateDO.getRoommatePhone())
                && !updateReqVO.getRoommatePhone().equals(roommateDO.getRoommatePhone())){
            // 根据证件号查用户
            MemberUserRespDTO memberUserRespDTO = memberUserApi.getUserByCardNo(roommateDO.getRoommateIdNumber()).getCheckedData();
            MobileModifyRecordCreateReqVO createReqVO = new MobileModifyRecordCreateReqVO()
                    .setUserName(updateReqVO.getRoommateName())
                    .setRealName(updateReqVO.getRoommateName())
                    .setOperator(SecurityFrameworkUtils.getLoginUser().getNickname())
                    .setBeforeMobile(roommateDO.getRoommatePhone())
                    .setAfterMobile(updateReqVO.getRoommatePhone())
                    .setCardNo(updateReqVO.getRoommateIdNumber());
            if(ObjectUtil.isNotEmpty(memberUserRespDTO)){
                createReqVO.setUserId(memberUserRespDTO.getId())
                        .setUserCreateTime(memberUserRespDTO.getCreateTime());
            }
            mobileModifyRecordApi.createRecord(createReqVO);
        }
    }

    @Override
    public void deleteRoommate(Long id) {
        // 校验存在
        ContractRoommateDO roommateDO = roommateMapper.selectById(id);
        if (roommateDO == null) {
            throw exception(ROOMMATE_NOT_EXISTS);
        }
        // 删除
        roommateMapper.deleteById(id);
    }


    @Override
    public ContractRoommateRespVO getRoommate(Long id) {
        ContractRoommateDO roommateDO = roommateMapper.selectById(id);
        if (roommateDO != null) {
            ContractRoommateRespVO convert = ContractRoommateConvert.INSTANCE.convert(roommateDO);
            ContractRoomDO contractRoomDO = contractRoomMapper.selectById(convert.getRoomContractId());
            if (contractRoomDO != null) {
                convert.setEmergencyContactName(contractRoomDO.getEmergencyContactName());
                convert.setEmergencyContactPhone(contractRoomDO.getEmergencyContactPhone());
                convert.setEmergencyContactRelationship(contractRoomDO.getEmergencyContactRelationship());
            }
            return convert;
        }
        return null;
    }

    @Override
    public List<ContractRoommateDO> getRoommateList(Long id) {
        LambdaQueryWrapper<ContractRoommateDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ContractRoommateDO::getRoomContractId, id)
                .ne(ContractRoommateDO::getStatus, 3);
        return roommateMapper.selectList(lambdaQueryWrapper);
    }

    @Override
    public ContractRoommateImportRespVO importRoommateList(List<ContractRoommateImportExcelVO> importUsers, boolean isUpdateSupport) {
        if (CollUtil.isEmpty(importUsers)) {
            throw exception(ROOMMATE_IMPORT_LIST_IS_EMPTY);
        }
        ContractRoommateImportRespVO respVO = ContractRoommateImportRespVO.builder().createUsernames(new ArrayList<>())
                .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
        //判断导入excel 寝室长是否符合要求
        checkRoomLeader(importUsers,respVO);
        importUsers.forEach(importUser -> {
            // 校验，判断是否有不符合的原因
            ContractRoommateDO roommateDO;
            try {
                validateRoommateCreateOrUpdate(importUser.getRoomId(), importUser.getRoommatePhone(), isUpdateSupport);
            } catch (ServiceException ex) {
                respVO.getFailureUsernames().put(importUser.getRoommateName(), ex.getMessage());
                return;
            }
            //校验身份证号码
            try {
                validateIDCard(importUser.getRoommateIdNumber(), importUser.getRoommateIdType());
            } catch (ServiceException ex) {
                respVO.getFailureUsernames().put(importUser.getRoommateName(), ex.getMessage());
                return;
            }
            // 判断如果不存在，在进行插入
            roommateDO = validateRoommateExists(importUser.getRoommatePhone(), importUser.getRoommateName(),
                    importUser.getRoomId());
            if (roommateDO == null) {
                RoomContractRespVO roomContract = contractRoomService.getRoomContract(importUser.getRoomId());
                if (roomContract == null) {
                    respVO.getFailureUsernames().put(importUser.getRoommateName(), "合同还未生成");
                    return;
                }
                ContractRoommateDO updateUser = ContractRoommateConvert.INSTANCE.convert(importUser);
                updateUser.setRoomContractId(roomContract.getId());
                // 此方法只有企业合同会调用  默认给企业
                updateUser.setContractCustomerType(CustomerTypeEnum.COMPANY.getCode());
                try {
                    //手机不允许重复
                    checkPhoneRepeat(roomContract.getId(), updateUser.getRoommatePhone());
                } catch (ServiceException e) {
                    respVO.getFailureUsernames().put(importUser.getRoommateName(), e.getMessage());
                    return;
                }
                //根据手机号获取用户id
                MemberUserRespDTO memberUser = getMemberUser(importUser.getRoommatePhone(), importUser.getRoommateName());
                updateUser.setMemberId(memberUser.getId());
                roommateMapper.insert(updateUser);
                //插入完成后，更新租客信息到房源
                ContractRoomDO contractRoomDO = contractRoomMapper.selectById(updateUser.getRoomContractId());
                updateRoommateData(contractRoomDO);
                //记录迁入
                dataLogging(updateUser, 1);
                respVO.getCreateUsernames().add(importUser.getRoommateName());

                //如果是寝室长，则需要将合同的memberId和未支付的杂费账单memberId更改当前用户
                if(importUser.getRoommateType()==1){
                    contractRoomMapper.updateMemberIdById(roomContract.getId(),memberUser.getId());
                    rentOrderMapper.updateMemberIdByContractIdUnPaid(roomContract.getId(),memberUser.getId());
                }
                return;
            }
            // 如果存在，判断是否允许更新
            if (!isUpdateSupport) {
                respVO.getFailureUsernames().put(importUser.getRoommateName(), ROOMMATE_USERNAME_EXISTS.getMsg());
                return;
            }
            ContractRoommateDO updateUser = ContractRoommateConvert.INSTANCE.convert(importUser);
            updateUser.setId(roommateDO.getId());
            roommateMapper.updateById(updateUser);
            respVO.getUpdateUsernames().add(importUser.getRoommateName());
        });
        return respVO;
    }

    /**
     * 同住人表里 同一间房间不允许相同手机号
     */
    private List<ContractRoommateDO> checkPhoneRepeat(Long contractId,String phone) {
        //需判断同住人表里 该房间未退房的不能存在相同手机号
        List<ContractRoommateDO> contractRoommateDOS = roommateMapper.selectRoommateListByContractId(contractId);
        if(CollectionUtils.isNotEmpty(contractRoommateDOS)){
            List<String> collect = contractRoommateDOS.stream().filter(e -> !RoommateStatusEnum.RENTED.getCode().toString().equals(e.getStatus())).map(ContractRoommateDO::getRoommatePhone).collect(Collectors.toList());
            if(collect.contains(phone)){
                throw exception(ROOM_HAS_SAME_PHONE);
            }
        }
        return contractRoommateDOS.stream().filter(e -> !"3".equals(e.getStatus())).collect(Collectors.toList());
    }

    /**
     * 校验寝室长
     */
    private void checkRoomLeader(List<ContractRoommateImportExcelVO> importUsers,ContractRoommateImportRespVO respVO) {
        String collect1 =
                importUsers.stream().filter(e -> e.getRoommateType() == null).map(m ->
                        String.format("房间编号【%d】,人员【%s】未设置寝室长字段", m.getRoomId(), m.getRoommateName()
                        )).collect(Collectors.joining(" \n "));
        if (StringUtils.isNotEmpty(collect1)) {
            throw exception0(ONLY_ONE_ROOM_HEAD.getCode(), collect1);
        }
        List<Long> hasLeaderRoomIds =
                importUsers.stream().filter(e -> e.getRoommateType() == 1).map(ContractRoommateImportExcelVO::getRoomId).collect(Collectors.toList());
        //一个房间只能有一个寝室长
        if (CollectionUtils.isNotEmpty(hasLeaderRoomIds)) {
            Set<Long> rooIdSet = new HashSet<>(hasLeaderRoomIds);
            if (rooIdSet.size() != hasLeaderRoomIds.size()) {
                throw exception(ONLY_ONE_ROOM_HEAD);
            }
            log.info("==hasLeaderRoomIds:{}", hasLeaderRoomIds);
            //查询是否存在重复寝室长查询出房间
            List<Long> longs = roommateMapper.countRoomHeadsByRoomIds(hasLeaderRoomIds);
            if (CollectionUtils.isNotEmpty(longs)) {
                //同一个房间 如果已存在寝室长直接抛异常
                List<Long> collect = longs.stream().distinct().collect(Collectors.toList());
                String collect2 =
                        importUsers.stream().filter(e -> e.getRoommateType() == 1 && collect.contains(e.getRoomId())).map(m ->
                                String.format("房间编号【%d】已存在寝室长，请修改文档后操作", m.getRoomId(), m.getRoommateName()
                                )).collect(Collectors.joining(" \n "));
                if (StringUtils.isNotEmpty(collect2)) {
                    throw exception0(ONLY_ONE_ROOM_HEAD.getCode(), collect2);
                }
                //添加报错提示
//                importUsers.stream().filter(e -> e.getRoommateType() == 1).map(m->{
//                    if (longs.contains(m.getRoomId())){
//                        respVO.getFailureUsernames().put(m.getFullRoomName(), ONLY_ONE_ROOM_HEAD.getMsg());
//                        importUsers.remove(m);
//                    }
//                    return null;
//                });
            }
        }
        log.info("数据参数importUsers1：{}",importUsers);
        log.info("数据参数respVO1：{}",respVO);
        //判断是否有寝室长 房间必须先有寝室长
        List<Long> noLeaderRoomIds = importUsers.stream().filter(e -> e.getRoommateType() == 0).map(ContractRoommateImportExcelVO::getRoomId).collect(Collectors.toList());
        noLeaderRoomIds.removeAll(hasLeaderRoomIds);
        if (CollectionUtils.isEmpty(noLeaderRoomIds)) {
            return;
        }
        LambdaQueryWrapper<ContractRoommateDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(ContractRoommateDO::getRoomId, noLeaderRoomIds)
                .eq(ContractRoommateDO::getRoommateType, 1)
                .ne(ContractRoommateDO::getStatus, 3);
        List<ContractRoommateDO> contractRoommateDOS = roommateMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(contractRoommateDOS)) {
            //添加报错提示
            importUsers.stream().filter(e -> e.getRoommateType() == 0).map(m->{
                if (noLeaderRoomIds.contains(m.getRoomId())){
                    respVO.getFailureUsernames().put(m.getFullRoomName(), ROOM_NO_LEADER.getMsg());
                    importUsers.remove(m);
                }
                return null;
            });
        }
        List<Long> collect = contractRoommateDOS.stream().map(ContractRoommateDO::getRoomId).collect(Collectors.toList());
        noLeaderRoomIds.removeAll(collect);
        if (CollectionUtils.isNotEmpty(noLeaderRoomIds)) {
            //添加报错提示
            importUsers.stream().filter(e -> e.getRoommateType() == 0).map(m->{
                if (noLeaderRoomIds.contains(m.getRoomId())){
                    respVO.getFailureUsernames().put(m.getFullRoomName(), ROOM_NO_LEADER.getMsg());
                    importUsers.remove(m);
                }
                return null;
            });
        }
        log.info("数据参数importUsers2：{}",importUsers);
        log.info("数据参数respVO2：{}",respVO);
    }

    private MemberUserRespDTO getMemberUser(String phone, String name) {
        MemberUserReqDTO memberUserReqDTO = new MemberUserReqDTO();
        memberUserReqDTO.setMobile(phone);
        memberUserReqDTO.setName(name);
        CommonResult<MemberUserRespDTO> userInfo = memberUserApi.getUserInfo(memberUserReqDTO);
        if (userInfo.getCode() != 0) {
            log.error("该手机号:{}无法创建会员信息", phone);
            throw exception(MEMBER_NOT_EXISTS);
        }
        return userInfo.getData();
    }

    @Override
    public List<ContractRoommateListReqVO> getContractRoommateList(Long contractId) {
        List<ContractRoommateDO> contractRoommateDOS = roommateMapper.selectList(ContractRoommateDO::getRoomContractId, contractId);
        if (CollectionUtils.isEmpty(contractRoommateDOS)){
            return null;
        }
        List<ContractRoommateListReqVO> reqVOS = ContractRoommateConvert.INSTANCE.convertList03(contractRoommateDOS);
        if (CollectionUtils.isNotEmpty(reqVOS)) {

            List<Long> user = reqVOS.stream().filter(f-> StringUtils.isNotBlank(f.getCreator())).map(m-> Long.parseLong(m.getCreator()))
                    .collect(Collectors.toList());
            Map<Long, String> creatorUser = null;
            Map<Long, String> operatorUser = null;
            if (CollectionUtils.isNotEmpty(user)){
                CommonResult<List<AdminUserRespDTO>> users = adminUserApi.getUsers(user);
                if (CollectionUtils.isNotEmpty(users.getData())){
                    creatorUser = users.getData().stream().filter(f -> StringUtils.isNotBlank(f.getNickname()))
                            .collect(Collectors.toMap(AdminUserRespDTO::getId, AdminUserRespDTO::getNickname, (oldWorking, newWorking) -> newWorking));
                }

            }

            if (CollectionUtils.isNotEmpty(user)){
                List<Long> operator = reqVOS.stream().map(ContractRoommateListReqVO::getCheckoutOperator)
                        .filter(Objects::nonNull).collect(Collectors.toList());
                CommonResult<List<AdminUserRespDTO>> operators = adminUserApi.getUsers(operator);
                if (CollectionUtils.isNotEmpty(operators.getData())){
                    operatorUser = operators.getData().stream().filter(f -> StringUtils.isNotBlank(f.getNickname()))
                            .collect(Collectors.toMap(AdminUserRespDTO::getId, AdminUserRespDTO::getNickname, (oldWorking, newWorking) -> newWorking));
                }
            }

            for (ContractRoommateListReqVO reqVO : reqVOS) {
                if(MapUtil.isNotEmpty(creatorUser)) {
                    reqVO.setCreatorName(StringUtils.isNotBlank(reqVO.getCreator()) ?
                            creatorUser.get(Long.parseLong(reqVO.getCreator())) : "");
                }
                if(MapUtil.isNotEmpty(operatorUser)) {
                    reqVO.setCheckoutOperatorName(ObjectUtil.isNotEmpty(reqVO.getCheckoutOperator()) ?
                            operatorUser.get(reqVO.getCheckoutOperator()) : "");
                }
            }
        }
        return reqVOS;
    }

    @Override
    public void roommateCheckout(Long id) {
        ContractRoommateDO roommateDO = roommateMapper.selectById(id);
        if (roommateDO == null) {
            return;
        }
        //查询租客合同对应的房间id
        ContractRoomDO contractRoomDO = contractRoomMapper.selectById(roommateDO.getRoomContractId());
        //判断是否有钱包退钱
        if(roommateDO.getContractCustomerType().equals(CustomerTypeEnum.COMPANY.getMsg())){
            CommonResult<Boolean> booleanCommonResult = financeAccountWithdrawApi.withdrawalRoomVerification(roommateDO.getRoommatePhone(), contractRoomDO.getCustomerCompanyId(), roommateDO.getRoomId());
            if (booleanCommonResult.isSuccess() && !booleanCommonResult.getData()){
                throw exception(HOUSE_WITHDRAWAL_NOT_PROCESSED);
            }
        }
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        roommateDO.setStatus("3");
        roommateDO.setCheckoutOperator(loginUserId);
        roommateDO.setCheckoutTime(LocalDate.now());
        roommateMapper.updateById(roommateDO);
        if (contractRoomDO != null) {
            deletePassWord(contractRoomDO.getRoomId(), roommateDO.getRoommatePhone());
            if (contractRoomDO.getCustomerType().equals(CustomerTypeEnum.COMPANY.getMsg())){
                try {
                    log.info("=====================开始推送===================={}",JSONObject.toJSONString(contractRoomDO));
                    //推送评价通知
                    pushServiceEvaluation(roommateDO.getRoomContractId(),PushServiceEvaluationTypeEnum.EMPLOYEE_RELOCATION.getMsg(),
                            PushServiceEvaluationTypeEnum.EMPLOYEE_RELOCATION.getCode(),roommateDO.getMemberId());
                    log.info("=====================结束推送====================");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        updateRoommateData(contractRoomDO);

    }

    private void deletePassWord(Long roomId, String phone) {
        log.info("开始删除同住人密码, roomId:{},phone:{}", roomId, phone);
        ResultModel resultModel = iotRoomDeviceApi.deletePassWordByMobile(roomId, phone);
        log.info("删除同住人密码 返回：{}", JSONObject.toJSONString(resultModel));
    }

    private void dataLogging(ContractRoommateDO roommateDO, int operationType) {
        if (roommateDO != null) {
            ContractRoommateLogDO contractRoommateLogDO = ContractRoommateConvert.INSTANCE.convertRoommate2RoommateLog(roommateDO);
            contractRoommateLogDO.setId(null);
            //获取房间id
            ContractRoomDO contractRoomDO = contractRoomService.get(roommateDO.getRoomContractId());
            if (contractRoomDO != null) {
                contractRoommateLogDO.setRoomId(contractRoomDO.getRoomId());
            }
            contractRoommateLogDO.setRoommateId(roommateDO.getId());
            contractRoommateLogDO.setOperationType(operationType);
            roommateLogMapper.insert(contractRoommateLogDO);
        }
    }

    private void dataLoggingBatch(List<ContractRoommateDO> roommateDO, int operationType) {
        if (CollectionUtils.isNotEmpty(roommateDO)) {
            List<ContractRoommateLogDO> contractRoommateLogDOS = ContractRoommateConvert.INSTANCE.convertList1(roommateDO);
            if (CollectionUtils.isNotEmpty(contractRoommateLogDOS)){
                List<ContractRoommateLogDO> collect = contractRoommateLogDOS.stream().map(m -> {
                    m.setRoommateId(m.getId());
                    m.setId(null);
                    m.setOperationType(operationType);
                    return m;
                }).collect(Collectors.toList());
                roommateLogMapper.insertBatch(collect);
            }
        }
    }

    @Override
    public PageResult<ContractRoommatePageRespVO> getRoommateListPage(ContractRoommatePageReqVO pageReqVO) {
        Page<ContractRoommatePageRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        roommateMapper.pageCompanyRoommateList(page, pageReqVO);
        List<ContractRoommatePageRespVO> data = page.getRecords();
        if (CollectionUtils.isNotEmpty(data)) {
            List<Long> ids = data.stream().map(ContractRoommatePageRespVO::getRoomId).collect(Collectors.toList());
            CommonResult<List<RoomHouseRespVo>> roomHouseByIds = roomHouseApi.getRoomHouseByIds(ids);

            if (CollectionUtils.isNotEmpty(roomHouseByIds.getData())) {
                Map<Long, String> collect = roomHouseByIds.getData().stream().filter(o -> StringUtils.isNotBlank(o.getFullRoomName()))
                        .distinct().collect(Collectors.toMap(RoomHouseRespVo::getId, RoomHouseRespVo::getFullRoomName));
                if (MapUtil.isNotEmpty(collect)) {
                    for (ContractRoommatePageRespVO datum : data) {
                        datum.setFullRoomName(collect.get(datum.getRoomId()));
                    }
                }
            }
        }
        PageResult<ContractRoommatePageRespVO> result = new PageResult<>();
        result.setList(data);
        result.setTotal(page.getTotal());
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getRoommateEmigration(Collection<Long> ids) {
        if (CollUtil.isNotEmpty(ids)) {
            for (Long id : ids) {
                roommateCheckoutCompany(id, false);
            }
        }
    }

    @Override
    public void changeRoommateType(Long id) {

        ContractRoommateDO roommateDO = roommateMapper.selectById(id);
        if (roommateDO != null) {
            List<ContractRoommateDO> contractRoommateDOS = roommateMapper.selectList(ContractRoommateDO::getRoomContractId, roommateDO.getRoomContractId());

            if (CollectionUtils.isNotEmpty(contractRoommateDOS)) {
                contractRoommateDOS.forEach(c -> c.setRoommateType(0));
                //当前房间所有人改为同住人
                roommateMapper.updateBatch(contractRoommateDOS, contractRoommateDOS.size());
                //修改寝室长
                roommateDO.setRoommateType(1);
                roommateDO.setUpdateTime(null);
                roommateMapper.updateById(roommateDO);
            }
            //如果是寝室长，则需要将合同的memberId和未支付的抄表账单memberId更改当前用户
            contractRoomMapper.updateMemberIdById(roommateDO.getRoomContractId(),roommateDO.getMemberId());
            rentOrderMapper.updateMemberIdByContractIdUnPaid(roommateDO.getRoomContractId(),roommateDO.getMemberId());
            log.info("操作修改寝室长，设置寝室长的同住人ID：{}，寝室长姓名：{}，操作人ID：{}，操作人：{}",id,roommateDO.getRoommateName(),
                    Objects.nonNull(SecurityFrameworkUtils.getLoginUserId())?SecurityFrameworkUtils.getLoginUserId():"",
                    Objects.nonNull(SecurityFrameworkUtils.getLoginUser())?SecurityFrameworkUtils.getLoginUser().getNickname():"");
        }
    }

    @Override
    public PageResult<ContractRoommateLogListVO> getRoommateLogListPage(ContractRoommateLogPageReqVO pageReqVO) {
        Page<ContractRoommateLogListVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        roommateLogMapper.pageCompanyRoommateLogList(page, pageReqVO);
        List<ContractRoommateLogListVO> data = page.getRecords();
        if (CollectionUtils.isNotEmpty(data)) {
            List<Long> ids = data.stream().map(ContractRoommateLogListVO::getRoomId).collect(Collectors.toList());
            CommonResult<List<RoomHouseRespVo>> roomHouseByIds = roomHouseApi.getRoomHouseByIds(ids);

            if (CollectionUtils.isNotEmpty(roomHouseByIds.getData())) {
                Map<Long, String> collect = roomHouseByIds.getData().stream().filter(o -> StringUtils.isNotBlank(o.getFullRoomName()))
                        .collect(Collectors.toMap(RoomHouseRespVo::getId, RoomHouseRespVo::getFullRoomName, (oldWorking, newWorking) -> newWorking));
                if (MapUtil.isNotEmpty(collect)) {
                    for (ContractRoommateLogListVO datum : data) {
                        datum.setFullRoomName(collect.get(datum.getRoomId()));
                    }
                }
            }
        }
        PageResult<ContractRoommateLogListVO> result = new PageResult<>();
        result.setList(data);
        result.setTotal(page.getTotal());
        return result;
    }

    @Override
    public Boolean getOnlyOne(Long id) {
        ContractRoommateDO roommateDO = roommateMapper.selectById(id);
        if (roommateDO == null) {
            throw exception(MEMBER_NOT_EXISTS);
        }
        //如果不是寝室长，直接返回
        if (roommateDO.getRoommateType().equals(0)) {
            return false;
        } else {
            //看房间是否还有住的有多少人
            QueryWrapper<ContractRoommateDO> qw = new QueryWrapper<>();
            qw.lambda().eq(ContractRoommateDO::getRoomContractId, roommateDO.getRoomContractId())
                    .eq(ContractRoommateDO::getStatus, 2);
            Long aLong = roommateMapper.selectCount(qw);
            log.info("房间还有:{}人", aLong);
            //如果房间只有一个人，且是寝室长。先判断是不是企业承担全部
            if (aLong <= 1) {
                ContractRoomDO contractRoomDO = contractRoomMapper.selectById(roommateDO.getRoomContractId());
                //企业承担全部
                if (contractRoomDO.getOrderShareMethod() == 1) {
                    return false;
                }//个人承担水电
                else {
                    return true;
                }
            }
            //房间人数大于1，且是寝室长,现转让寝室长再迁出
            throw exception(THE_CURRENT_DORMITORY_HAS_A_DORMITORY_LEADER);
        }
    }

    @Override
    public void roommateCheckoutCompany(Long id, Boolean isOne) {
        ContractRoommateDO roommateDO = roommateMapper.selectById(id);
        if (roommateDO == null) {
            return;
        }
        //查询租客合同对应的房间id
        ContractRoomDO contractRoomDO = contractRoomMapper.selectById(roommateDO.getRoomContractId());
        //判断是否有钱包退钱
        CommonResult<Boolean> booleanCommonResult = financeAccountWithdrawApi.withdrawalRoomVerification(roommateDO.getRoommatePhone(), contractRoomDO.getCustomerCompanyId(), roommateDO.getRoomId());
        if (booleanCommonResult.isSuccess() && !booleanCommonResult.getData()){
            throw exception(HOUSE_WITHDRAWAL_NOT_PROCESSED);
        }
        //需要计算钱包金额是正负
        if (isOne) {
            //主住人需check钱包是否有欠款
            //获取用户
            CommonResult<FinanceAccountDTO> individual = financeAccountApi.getAccount(roommateDO.getMemberId().toString(), FinanceCustomerTypeEnum.INDIVIDUAL.name());
            if (individual.getCode() != 0) {
                throw exception(TENANT_WALLET_ACQUISITION_FAILED);
            }
            if (individual.getData() != null) {
                FinanceAccountDTO data = individual.getData();
                BigDecimal balance = data.getBalance();
                //余额大于等于0，可以迁出
                if (balance.compareTo(BigDecimal.ZERO) >= 0) {
                    Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
                    roommateDO.setStatus("3");
                    roommateDO.setCheckoutOperator(loginUserId);
                    roommateDO.setCheckoutTime(LocalDate.now());
                    roommateMapper.updateById(roommateDO);
                    dataLogging(roommateDO, 0);
                    try {
                        log.info("=====================开始推送===================={}",JSONObject.toJSONString(contractRoomDO));
                        //推送评价通知
                        pushServiceEvaluation(roommateDO.getRoomContractId(),PushServiceEvaluationTypeEnum.EMPLOYEE_RELOCATION.getMsg(),
                                PushServiceEvaluationTypeEnum.EMPLOYEE_RELOCATION.getCode(),roommateDO.getMemberId());
                        log.info("=====================结束推送====================");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    //水电费未结清，不能迁出
                    throw exception(UTILITY_BILLS_ARE_OUTSTANDING);
                }
            }
        }//同住人直接迁出
        else {
            Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
            roommateDO.setStatus("3");
            roommateDO.setCheckoutOperator(loginUserId);
            roommateDO.setCheckoutTime(LocalDate.now());
            roommateMapper.updateById(roommateDO);
            log.info("=====================开始推送====================");
            try {
                //推送评价通知
                pushServiceEvaluation(roommateDO.getRoomContractId(),PushServiceEvaluationTypeEnum.EMPLOYEE_RELOCATION.getMsg(),
                        PushServiceEvaluationTypeEnum.EMPLOYEE_RELOCATION.getCode(),roommateDO.getMemberId());
                log.info("=====================结束推送====================");
            } catch (Exception e) {
                e.printStackTrace();
            }
            //迁出记录
            dataLogging(roommateDO, 0);
        }
        if (contractRoomDO != null) {
            updateRoommateData(contractRoomDO);
            deletePassWord(contractRoomDO.getRoomId(), roommateDO.getRoommatePhone());
        }
    }

    private ContractRoommateDO validateRoommateExists(String roommatePhone, String roommateName, Long roomId) {
        if (StringUtils.isNotBlank(roommateName)) {
            //获取合同id
            LambdaQueryWrapper<ContractRoommateDO> qw = new LambdaQueryWrapper<>();
            qw.eq(StringUtils.isNotBlank(roommateName), ContractRoommateDO::getRoommateName, roommateName)
                    .eq(Objects.nonNull(roomId), ContractRoommateDO::getRoomId, roomId)
                    .eq(StringUtils.isNotBlank(roommatePhone), ContractRoommateDO::getRoommatePhone, roommatePhone)
                    .ne(ContractRoommateDO::getStatus,3)
                    .eq(ContractRoommateDO::getDeleted,false);
            return roommateMapper.selectOne(qw);
        }
        return null;
    }

    private void validateRoommateCreateOrUpdate(Long roomId, String roommatePhone, boolean isUpdateSupport) {
        //校验房间是否存在
        validateRoomExists(roomId);
        //校验手机号格式是否正确
        validatePhoneExists(roommatePhone);
    }

    private void validatePhoneExists(String roommatePhone) {
        if (StringUtils.isNotBlank(roommatePhone)) {
            if (!Pattern.matches("^1[3-9]\\d{9}$", roommatePhone)) {
                throw exception(ROOMMATE_PHONE_FORMAT_ERROR);
            }
        }
    }

    public void validateIDCard(String idCard, Integer roommateIdType) {
        //进行身份证校验
        if (roommateIdType != null && roommateIdType == 1) {
            String regex = "^\\d{17}[\\d|xX]$";
            if (!idCard.matches(regex)) {
                throw exception0(ROOMMATE_PHONE_FORMAT_ERROR.getCode(), "身份证号码错误！");
            }
        }
    }

    private void validateRoomExists(Long roomId) {
        if (roomId != null) {
            CommonResult<RoomHouseRespVo> roomHouseinfoById = roomHouseApi.getRoomHouseinfoById(roomId);
            if (roomHouseinfoById.getCode() != 0) {
                throw exception(ROOM_NOT_EXIST);
            }
        }
    }


    @Override
    public List<ContractRoommateDO> getByParam(ContractRoommateDO param) {
        if (Objects.isNull(param)) {
            return null;
        }
        LambdaQueryWrapper<ContractRoommateDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Objects.nonNull(param.getContractCustomerType()), ContractRoommateDO::getContractCustomerType, param.getContractCustomerType());
        queryWrapper.eq(Objects.nonNull(param.getMemberId()), ContractRoommateDO::getMemberId, param.getMemberId());
        queryWrapper.eq(Objects.nonNull(param.getRoommatePhone()), ContractRoommateDO::getRoommatePhone, param.getRoommatePhone());
        queryWrapper.eq(Objects.nonNull(param.getSignSecurityProtocol()), ContractRoommateDO::getSignSecurityProtocol, param.getSignSecurityProtocol());
        queryWrapper.eq(Objects.nonNull(param.getProtocolTransactionNo()), ContractRoommateDO::getProtocolTransactionNo, param.getProtocolTransactionNo());
        queryWrapper.eq(Objects.nonNull(param.getRoomContractId()), ContractRoommateDO::getRoomContractId, param.getRoomContractId());
        queryWrapper.eq(Objects.nonNull(param.getRoommateType()), ContractRoommateDO::getRoommateType, param.getRoommateType());
        queryWrapper.eq(Objects.nonNull(param.getRoomId()), ContractRoommateDO::getRoomId, param.getRoomId());
        queryWrapper.eq(StringUtils.isNotBlank(param.getStatus()), ContractRoommateDO::getStatus, param.getStatus());
        queryWrapper.orderByDesc(ContractRoommateDO::getCreateTime);
        return roommateMapper.selectList(queryWrapper);
    }


    @Override
    public List<ContractRoommateDO> getRequireSignSafeRoommateList(Long memberNo) {
        // 查同住人表 1手机号 2类型-企业 3签约状态-未签协议 4待入住
        ContractRoommateDO param = new ContractRoommateDO();
        param.setMemberId(memberNo);
        param.setContractCustomerType(CustomerTypeEnum.COMPANY.getCode());
        param.setSignSecurityProtocol(false);
        param.setStatus("1");
        List<ContractRoommateDO> roommateList = getByParam(param);
        if (CollectionUtils.isEmpty(roommateList)) {
            return null;
        }
        List<Long> contractIds = roommateList.stream().map(ContractRoommateDO::getRoomContractId).collect(Collectors.toList());
        List<ContractRoomDO> contractList = contractRoomService.getList(contractIds);
        if (CollectionUtils.isEmpty(contractList)) {
            throw exception(CONTRACT_DOES_NOT_EXISTS);
        }
        // 过滤出已入住的合同
        contractList = contractList.stream().filter(c -> ContractStatusEnum.CHECK_IN.getCode().equals(c.getContractStatus())).collect(Collectors.toList());

        Map<Long, ContractRoomDO> contractMap = contractList.stream().collect(Collectors.toMap(ContractRoomDO::getId, v -> v));
        // 过滤同住人数据
        roommateList = roommateList.stream().filter(r -> contractMap.containsKey(r.getRoomContractId())).collect(Collectors.toList());
        return roommateList;
    }


    @Override
    public void updateRoommateById(ContractRoommateDO update) {
        if (Objects.nonNull(update) && Objects.nonNull(update.getId())) {
            roommateMapper.updateById(update);
        }
    }

    // ****此方法签约回调调用，无法获取到tenantId、登录用户等数据****
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkInSuccess(ContractRoommateDO param) {
        log.info("签署安全协议检查是否成功：{}",JSONObject.toJSONString(param));
        if (Objects.isNull(param) || Objects.isNull(param.getTenantId())) {
            return;
        }
        TenantUtils.execute(param.getTenantId(),()->{
            // 更新同住人数据
            updateRoommateById(param);
            try {
                // 查询合同信息
                Long roomContractId = param.getRoomContractId();
                if (Objects.nonNull(roomContractId)) {
                    ContractRoomDO contractRoomDO = contractRoomService.get(roomContractId);
                    if (Objects.nonNull(contractRoomDO)) {
                        // 下发密码
                        String nickName = "";
                        if (StringUtils.isNotBlank( param.getCreator())) {
                            CommonResult<AdminUserRespDTO> user = adminUserApi.getUser(Long.parseLong( param.getCreator()));
                            if (user.isSuccess() && user.getData() != null) {
                                nickName = user.getData().getNickname();
                            }
                        }
                        //企业合同同住人下发密码，租客合同同住人不下发密码只下发承住人
                        if(CustomerTypeEnum.COMPANY.getCode().equals(contractRoomDO.getCustomerType())){
                            issuePassword(contractRoomDO.getRoomId(), param.getRoommateName(), param.getRoommatePhone(), contractRoomDO.getStartTime(), contractRoomDO.getEndTime(), nickName);
                        }
                        log.info("=====================开始推送===================={}",JSONObject.toJSONString(contractRoomDO));
                        //推送评价通知
                        pushServiceEvaluation(roomContractId,PushServiceEvaluationTypeEnum.EMPLOYEE_CHECK_IN.getMsg(),
                                PushServiceEvaluationTypeEnum.EMPLOYEE_CHECK_IN.getCode(),param.getMemberId());
                        log.info("=====================结束推送===================={}",JSONObject.toJSONString(contractRoomDO));
                    }
                }
            } catch (Exception e) {
                log.error("签署安全协议回调，修改状态，异常信息：", e);
            }
        });
    }


    private void pushServiceEvaluation(Long roomContractId,String content,Integer commentType,Long memberId) {
        MemberMessageDTO memberMessageDTO = new MemberMessageDTO();
        ContractRoomDO contractRoomDO = contractRoomService.get(roomContractId);
        log.info("=====================推送中===================={}",JSONObject.toJSONString(contractRoomDO));
        if (contractRoomDO != null){
            memberMessageDTO.setUserId(memberId);
            memberMessageDTO.setContent(content);
            memberMessageDTO.setType(1);
            memberMessageDTO.setStatus(1);
            memberMessageDTO.setDestination(3);
            memberMessageDTO.setCreator(contractRoomDO.getCreator());

            memberMessageDTO.setSteward(contractRoomDO.getSignerName());
            memberMessageDTO.setStewardId(contractRoomDO.getSignerId());

            memberMessageDTO.setCommentType(commentType);
            memberMessageDTO.setApartmentName(contractRoomDO.getApartmentName());
            memberMessageDTO.setRoomId(contractRoomDO.getRoomId());
            memberMessageDTO.setSignDay(contractRoomDO.getSignedTime());
            log.info("============{}============",JSONObject.toJSONString(memberMessageDTO));
            memberMessageApi.create(memberMessageDTO);
        }
    }

    @Override
    public void roommateTransfer(Long originalContractId, Long currentContractId, Long roomId) {
        if (Objects.isNull(originalContractId) || Objects.isNull(currentContractId)){
            return;
        }
        // 查询原合同所有入住人
        List<ContractRoommateDO> contractRoommateDOS = roommateMapper.selectList(ContractRoommateDO::getRoomContractId, originalContractId);
        // 批量迁出
        batchMovingOut(originalContractId);
        /*// 只迁移同住人 主住人续租时会迁过来
        contractRoommateDOS = contractRoommateDOS.stream().filter(r -> 0 == r.getRoommateType()).collect(Collectors.toList());
        */
        // 批量迁入
        contractRoommateDOS.forEach(r ->{
            r.setId(null);
            r.setCreateTime(null);
            r.setUpdateTime(null);
            if (Objects.nonNull(roomId)){
                r.setRoomId(roomId);
            }
            r.setRoomContractId(currentContractId);
        });
        roommateMapper.insertBatch(contractRoommateDOS);
        // 迁入记录
        List<ContractRoommateLogDO> movingInRoommateLogList = contractRoommateDOS.stream()
                .filter(r -> RoommateStatusEnum.CHECKED_ID.getCode().toString().equals(r.getStatus()))
                .map(r -> {
                    ContractRoommateLogDO logDO = ContractRoommateConvert.INSTANCE.convertRoommate2RoommateLog(r);
                    logDO.setOperationType(ONE);
                    logDO.setId(null);
                    return logDO;
                }).collect(Collectors.toList());
        roommateLogMapper.insertBatch(movingInRoommateLogList);
    }



    /**
     * 批量迁出
     */
    private void batchMovingOut(Long roomContractId) {
        if (Objects.isNull(roomContractId)) {
            return;
        }
        LambdaQueryWrapper<ContractRoommateDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractRoommateDO::getRoomContractId, roomContractId);
        queryWrapper.eq(ContractRoommateDO::getStatus, RoommateStatusEnum.CHECKED_ID.getCode());
        List<ContractRoommateDO> checkInRoommateList = roommateMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(checkInRoommateList)){
            // 记录迁出记录
            List<ContractRoommateLogDO> roommateLogList = checkInRoommateList.stream().map(r -> {
                ContractRoommateLogDO logDO = ContractRoommateConvert.INSTANCE.convertRoommate2RoommateLog(r);
                logDO.setOperationType(ZERO);
                logDO.setId(null);
                return logDO;
            }).collect(Collectors.toList());
            roommateLogMapper.insertBatch(roommateLogList);
        }

        // 批量迁出已入住的入住人
        LambdaUpdateWrapper<ContractRoommateDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ContractRoommateDO::getRoomContractId, roomContractId);
        updateWrapper.eq(ContractRoommateDO::getStatus, RoommateStatusEnum.CHECKED_ID.getCode());
        updateWrapper.set(ContractRoommateDO::getStatus, RoommateStatusEnum.RENTED.getCode());
        updateWrapper.set(ContractRoommateDO::getCheckoutTime, LocalDate.now());
        roommateMapper.update(null, updateWrapper);
        // 删除待入住的入住人
        LambdaQueryWrapper<ContractRoommateDO> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(ContractRoommateDO::getRoomContractId, roomContractId);
        deleteWrapper.eq(ContractRoommateDO::getStatus, RoommateStatusEnum.PENDING_CHECK_IN.getCode());
        roommateMapper.delete(deleteWrapper);
    }

    @Override
    public List<ContractRoommateDO> getListByContractId(Long contractId) {
        LambdaQueryWrapper<ContractRoommateDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractRoommateDO::getRoomContractId, contractId);
        queryWrapper.eq(ContractRoommateDO::getRoommateType,0);
        queryWrapper.ne(ContractRoommateDO::getStatus, RoommateStatusEnum.CHECKED_ID.getCode());
        return roommateMapper.selectList(queryWrapper);

    }

    /**
    * 根据合同ids  查询同住人 信息
    * */
    @Override
    public List<Long> getContractRoommateList(List<Long> contractIds) {
        LambdaQueryWrapper<ContractRoommateDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractRoommateDO::getStatus, RoommateStatusEnum.CHECKED_ID.getCode())
                .in(ContractRoommateDO::getRoomContractId, contractIds);
        List<ContractRoommateDO> contractRoommateDOS = roommateMapper.selectList(queryWrapper);
        List<Long> result = contractRoommateDOS.stream()
                    .filter(item -> item.getMemberId() != null).distinct()
                    .map(ContractRoommateDO::getMemberId).collect(Collectors.toList());
        return result;
    }
}
